import requests
import traceback

from django.core.management.base import BaseCommand
from queue import Queue
from threading import Thread

from models.retry_request import RetryRequests
from models.user import OutUrls
from utilities.log import log_err, log_info
from utilities.api_send_message import send_message


MAX_RETRY_COUNT = 50


class T(Thread):
    def __init__(self, request_id, q: Queue, request_data, method=None, obj_url=None, *args, **kwargs):
        self.q = q
        self.request_id = request_id
        self.method = method
        self.request_data = request_data
        self.obj_url = obj_url
        super(T, self).__init__(*args, **kwargs)

    def run(self) -> None:
        obj_request = RetryRequests.objects(request_id=self.request_id).first()
        if not obj_request:
            log_info(f"Request {self.request_id} not found")
            self.q.get()
            self.q.task_done()

        try:
            if self.obj_url:
                flag, _ = send_message(self.request_data, url_obj=self.obj_url)
            else:
                if self.method == 'GET':
                    resp = requests.get(**self.request_data)
                else:
                    resp = requests.post(**self.request_data)
                flag = bool(resp.status_code == 200)

            log_info(f"Retry request id {obj_request.request_id}, method: {self.method}, request_data: {self.request_data}.")
            if flag:
                # logger.info(f"Retry successful, remove {obj_request.request_id}.")
                obj_request.delete()
            else:
                assert False
        except Exception:
            obj_request.update(inc__send_count=1)
            log_info(f"Retry failed {obj_request.request_id}")
            # log_err(e)
            traceback.print_exc()
            if obj_request.send_count + 1 >= 50:
                obj_request.delete()
        finally:
            self.q.get()
            self.q.task_done()


def retry_requests():
    queue = Queue(maxsize=100)

    for item in RetryRequests.objects.filter():
        if item.url_id:
            obj_url = OutUrls.objects(url_id=item.url_id).first()
            send_message(item.body, url_obj=obj_url)
            t = T(item.request_id, q=queue, request_data=item.body, obj_url=obj_url)
        else:
            t = T(
                request_id=item.request_id,
                method=item.method,
                request_data={'headers': item.headers, 'body': item.body}, q=queue
            )

        queue.put(item.request_id)
        t.start()

    queue.join()


class Command(BaseCommand):
    def handle(self, *args, **options):
        retry_requests()
